<template>
  <div class="topo-background" :style="{ height: availableHeight + 'px'}">
    <div id="visualization" class="network" style="height: 100%" />
    <FormDialog
      title="属性信息"
      :drawer="true"
      :show="dialogAttrViewVisible"
      width="30%"
      @on-ok="onCloseAttrView"
      @on-cancel="onCloseAttrView"
    >
      <el-form v-if="dialogAttrViewVisible" ref="attrView" label-width="180px" size="mini">
        <el-form-item key="name" label="名称">
          <span>{{ instance.name }}</span>
        </el-form-item>
        <el-form-item key="code" label="编码">
          <span>{{ instance.code }}</span>
        </el-form-item>
        <el-form-item v-for="attr in instance.attrs" :key="attr.field" :label="attr.name" :prop="attr.field">
          <span v-if="getAttrDType(attr.field) !== 'foreign'">{{ getAttrValue(attr.field, attr.value) }}</span>
          <router-link v-else :to="'/cmdb/instances/' + attr.value" class="el-button el-button--text el-button" style="padding-top: 0;">
            <foreign-select v-model="attr.value" :disabled="true" :schema="getForeignKey(attr.field)" :width="150" />
          </router-link>
        </el-form-item>
      </el-form>
    </FormDialog>
  </div>
</template>

<script>
// 按需引入
import vis from 'vis'
import 'vis/dist/vis.min.css'
import resize from '@neu/biz-core/mixins/resize'
import FormDialog from '@neu/biz-core/components/FormDialog'
import { getTopo } from '@neu/cmdb-ui/api/business'
import { detail as getTopoLayout, update as updateLayout } from '@neu/cmdb-ui/api/topolayouts'
import { detail as instanceDetail } from '@neu/cmdb-ui/api/instance'
import { parseTime } from '@neu/biz-core/utils'

export default {
  name: 'VisNetWork',
  components: {
    FormDialog
  },
  mixins: [resize],
  props: {
    businessId: {
      required: true,
      type: String
    }
  },
  data() {
    return {
      network: null,
      nodes: [],
      edges: [],
      dialogAttrViewVisible: false,
      instance: {
        name: '',
        code: '',
        attrs: [],
        schemaAttrs: []
      }
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.dataReload()
    })
  },
  methods: {
    initNetwork() {
      const that = this
      // create an array with nodes
      var nodes = new vis.DataSet(this.nodes)

      // create an array with edges
      var edges = new vis.DataSet(this.edges)

      // create a network
      var container = document.querySelector('#visualization')

      // provide the data in the vis format
      var data = {
        nodes: nodes,
        edges: edges
      }
      var options = {
        // layout: {
        //   hierarchical: {
        //     direction: 'DU',
        //     sortMethod: 'directed'
        //   }
        // }
        // barnesHut: {
        //   hierarchicalRepulsion: {
        //     avoidOverlap: 1
        //   }
        // }
        // 布局
        // layout: {
        //   // 分级
        //   hierarchical: {
        //     // levelSeparation: 500, // 不同层次之间的距离
        //     // nodeSpacing: 200, // 自由轴上节点之间最小距离
        //     // treeSpacing: 500, // 不同树之间的距离
        //     // 方向
        //     direction: 'UD',
        //     sortMethod: 'hubsize' // hubsize, directed
        //   }
        // },
        // edges: {
        //   smooth: {
        //     enabled: false
        //   }
        // },
        physics: {
          enabled: false
        }
      }

      // initialize your network!
      this.network = new vis.Network(container, data, options)
      this.network.on('click', function(params) {
        const schemaCode = this.getNodeAt(params.pointer.DOM)
        const node = that.nodes.find(it => it.id === schemaCode)
        if (node) {
          that.routeTo(node._id)
        }
      })
      this.network.on('dragEnd', function(params) {
        updateLayout(that.businessId, { data: JSON.stringify(this.getPositions()) })
      })
    },
    dataReload() {
      getTopo(this.businessId).then(response => {
        const nodes = response.data.nodes
        nodes.forEach(n => {
          if (n.icon) {
            n.image = n.icon
            n.shape = 'image'
          }
        })
        this.nodes = nodes
        var edges = response.data.edges
        edges.forEach(e => {
          e.color = { color: 'rgba(30,30,30,0.2)', highlight: 'blue' }
        })
        this.edges = edges

        getTopoLayout(this.businessId).then(res => {
          if (res.data && res.data.data) {
            const layout = JSON.parse(res.data.data)
            nodes.forEach(it => {
              if (layout.hasOwnProperty(it.id)) {
                it.x = layout[it.id].x
                it.y = layout[it.id].y
              }
            })
          }
          this.initNetwork()
        })
      })
    },
    getOtherContentHeight() {
      const baseInfoSel = document.querySelector('.business-edit-container .base-info')
      const baseInfoHeight = baseInfoSel ? baseInfoSel.offsetHeight : 0

      const elTabsHeaderSel = document.querySelector(
        '.business-edit-container .el-tabs__header'
      )
      const elTabsHeaderHeight = elTabsHeaderSel
        ? elTabsHeaderSel.offsetHeight + 15
        : 0
      return baseInfoHeight + elTabsHeaderHeight + 16 + 5
    },
    routeTo(instanceId) {
      // this.$router.push({
      //   name: 'cmdb_instances_detail',
      //   params: { id: instanceId }
      // })
      instanceDetail(instanceId).then(response => {
        const attrs = response.data.attrs
        const schemaAttrs = response.data.schemadef.attrs
        this.instance.code = response.data.code
        this.instance.name = response.data.name
        this.instance.schemaAttrs = schemaAttrs
        const mAttrs = attrs.map(it => {
          const attr = {
            field: it.key,
            name: it.key,
            value: it.value
          }
          const schemaAttr = schemaAttrs.find(a => a.field === it.key)
          if (schemaAttr) attr.name = schemaAttr.name
          return attr
        })

        this.instance.attrs = mAttrs
        this.dialogAttrViewVisible = true
      })
    },
    getAttrDType(k) {
      const schemaAttr = this.instance.schemaAttrs.find(it => it.field === k)
      return schemaAttr ? schemaAttr.dtype : 'string'
    },
    // 获取格式化属性值
    getAttrValue(k, v) {
      const attr = this.instance.schemaAttrs.find(it => it.field === k)
      if (attr.dtype === 'date') {
        return parseTime(v)
      } else if (attr.dtype === 'enum') {
        const enumItem = attr.enums.find(e => e.value === v)
        return enumItem ? enumItem.label : ''
      } else if (attr.dtype === 'bool') {
        return v ? '是' : '否'
      }
      return v !== null ? v : '未设置'
    },
    // 获取外键属性的定义
    getForeignKey(k) {
      const schemaAttr = this.instance.schemaAttrs.find(it => it.field === k)
      return schemaAttr ? schemaAttr.dvalue : ''
    },
    onCloseAttrView() {
      this.dialogAttrViewVisible = false
    }
  }
}
</script>

<style scoped>
  .topo-background {
    background-image: linear-gradient(#eef1f5 1px,transparent 0),linear-gradient(90deg,#eef1f5 1px,transparent 0);
    background-size: 10px 10px;
  }
</style>
